﻿#include <xy/ais/object.h>

namespace xy
{

namespace ais
{

bool object::collision(msg_mouse *msg)
{
    // do nothing by default
    return false;
}

void object::set_parent(object *parent)
{
    m_parent = parent;
}

void object::add_child(std::shared_ptr<object> child)
{
    m_children.push_back(child);
    child->set_parent(this);
}

object::Status object::status() const
{
    return m_status;
}

void object::set_status(Status status)
{
    m_status = status;
}

void object::handle_msg(std::shared_ptr<msg> msg)
{
    for (auto child : m_children)
        child->handle_msg(msg);
    msg->accept(this);
}

void object::visit(msg_init *msg)
{
    // do nothing by default
}

void object::visit(msg_update *msg)
{
    if (m_renderer)
        m_renderer->update(this);
}

void object::visit(msg_paint *msg)
{
    if (m_renderer && m_status != Status::Hidden)
        m_renderer->draw(this);
}

void object::visit(msg_visible *msg)
{
    if (msg->show)
        m_status = Status::Shown;
    else
        m_status = Status::Hidden;
}

void object::visit(msg_move *msg)
{
    if (m_parent)
        m_parent->handle_msg(std::make_shared<msg_update>());
    else
        handle_msg(std::make_shared<msg_update>());
}

void object::visit(msg_mouse *msg)
{
    // 隐藏则不处理鼠标消息
    if (m_status == Status::Hidden)
        return;

    switch (msg->status)
    {
    case msg_mouse::Press: {
        auto visibleMsg = std::make_shared<msg_visible>();

        // 由于子节点先处理 Mouse 消息，如果坐标轴被选中，当前节点会接收到 Show 消息，状态变为 Shown
        // 从而不会处理第一个分支导致坐标轴隐藏
        if (m_status == Status::Pressed)
        {
            m_status = Status::Shown;
            visibleMsg->show = false;
            for (auto child : m_children)
                child->handle_msg(visibleMsg);
        }
        else if (collision(msg))
        {
            visibleMsg->show = true;
            if (m_parent)
                m_parent->handle_msg(visibleMsg);
            else
            {
                for (auto child : m_children)
                    child->handle_msg(visibleMsg);
            }
        }
        break;
    }
    case msg_mouse::Move: {
        // 同一时刻只能有一个 hovered 对象，因此检测后设置状态为 Shown
        // 在 context 中设置 hovered 状态
        if (m_status == Status::Shown || m_status == Status::Hovered)
        {
            collision(msg);
            m_status = Status::Shown;
        }
        break;
    }
    case msg_mouse::Release: {
        break;
    }
    }
}

void object::visit(msg_destroy *msg)
{
    m_status = Status::Dead;
}

} // namespace ais

} // namespace xy
